home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Codigo / hh / rsource.exe / Hexen Source / P_MAP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-22  |  54.4 KB  |  2,297 lines

  1.  
  2. //**************************************************************************
  3. //**
  4. //** p_map.c : Heretic 2 : Raven Software, Corp.
  5. //**
  6. //** $RCSfile: p_map.c,v $
  7. //** $Revision: 1.107 $
  8. //** $Date: 95/10/13 04:26:47 $
  9. //** $Author: paul $
  10. //**
  11. //**************************************************************************
  12.  
  13. #include "h2def.h"
  14. #include "p_local.h"
  15. #include "soundst.h"
  16.  
  17. static void CheckForPushSpecial(line_t *line, int side, mobj_t *mobj);
  18.  
  19. /*
  20. ===============================================================================
  21.  
  22. NOTES:
  23.  
  24.  
  25. ===============================================================================
  26. */
  27.  
  28. /*
  29. ===============================================================================
  30.  
  31. mobj_t NOTES
  32.  
  33. mobj_ts are used to tell the refresh where to draw an image, tell the world simulation when objects are contacted, and tell the sound driver how to position a sound.
  34.  
  35. The refresh uses the next and prev links to follow lists of things in sectors as they are being drawn.  The sprite, frame, and angle elements determine which patch_t is used to draw the sprite if it is visible.  The sprite and frame values are allmost allways set from state_t structures.  The statescr.exe utility generates the states.h and states.c files that contain the sprite/frame numbers from the statescr.txt source file.  The xyz origin point represents a point at the bottom middle of the sprite (between the feet of a biped).  This is the default origin position for patch_ts grabbed with lumpy.exe.  A walking creature will have its z equal to the floor it is standing on.
  36.  
  37. The sound code uses the x,y, and subsector fields to do stereo positioning of any sound effited by the mobj_t.
  38.  
  39. The play simulation uses the blocklinks, x,y,z, radius, height to determine when mobj_ts are touching each other, touching lines in the map, or hit by trace lines (gunshots, lines of sight, etc). The mobj_t->flags element has various bit flags used by the simulation.
  40.  
  41.  
  42. Every mobj_t is linked into a single sector based on it's origin coordinates.
  43. The subsector_t is found with R_PointInSubsector(x,y), and the sector_t can be found with subsector->sector.  The sector links are only used by the rendering code,  the play simulation does not care about them at all.
  44.  
  45. Any mobj_t that needs to be acted upon be something else in the play world (block movement, be shot, etc) will also need to be linked into the blockmap.  If the thing has the MF_NOBLOCK flag set, it will not use the block links. It can still interact with other things, but only as the instigator (missiles will run into other things, but nothing can run into a missile).   Each block in the grid is 128*128 units, and knows about every line_t that it contains a piece of, and every interactable mobj_t that has it's origin contained.
  46.  
  47. A valid mobj_t is a mobj_t that has the proper subsector_t filled in for it's xy coordinates and is linked into the subsector's sector or has the MF_NOSECTOR flag set (the subsector_t needs to be valid even if MF_NOSECTOR is set), and is linked into a blockmap block or has the MF_NOBLOCKMAP flag set.  Links should only be modified by the P_[Un]SetThingPosition () functions.  Do not change the MF_NO? flags while a thing is valid.
  48.  
  49.  
  50. ===============================================================================
  51. */
  52.  
  53. fixed_t         tmbbox[4];
  54. mobj_t          *tmthing;
  55. mobj_t             *tsthing;
  56. int                     tmflags;
  57. fixed_t         tmx, tmy;
  58.  
  59. boolean         floatok;    // if true, move would be ok if
  60.                             // within tmfloorz - tmceilingz
  61.  
  62. fixed_t tmfloorz, tmceilingz, tmdropoffz;
  63. int tmfloorpic;
  64.  
  65. // keep track of the line that lowers the ceiling, so missiles don't explode
  66. // against sky hack walls
  67. line_t *ceilingline;
  68.  
  69. // keep track of special lines as they are hit, but don't process them
  70. // until the move is proven valid
  71. #define MAXSPECIALCROSS 8
  72. line_t *spechit[MAXSPECIALCROSS];
  73. int numspechit;
  74.  
  75. mobj_t *onmobj; // generic global onmobj...used for landing on pods/players
  76. mobj_t *BlockingMobj;
  77.  
  78. /*
  79. ===============================================================================
  80.  
  81.                     TELEPORT MOVE
  82.  
  83. ===============================================================================
  84. */
  85.  
  86. /*
  87. ==================
  88. =
  89. = PIT_StompThing
  90. =
  91. ==================
  92. */
  93.  
  94. boolean PIT_StompThing (mobj_t *thing)
  95. {
  96.     fixed_t         blockdist;
  97.  
  98.     if (!(thing->flags & MF_SHOOTABLE) )
  99.         return true;
  100.  
  101.     blockdist = thing->radius + tmthing->radius;
  102.     if ( abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist )
  103.         return true;            // didn't hit it
  104.  
  105.     if (thing == tmthing)
  106.         return true;            // don't clip against self
  107.  
  108.     if(!(tmthing->flags2&MF2_TELESTOMP))
  109.     { // Not allowed to stomp things
  110.         return(false);
  111.     }
  112.  
  113.     P_DamageMobj (thing, tmthing, tmthing, 10000);
  114.  
  115.     return true;
  116. }
  117.  
  118.  
  119. /*
  120. ===================
  121. =
  122. = P_TeleportMove
  123. =
  124. ===================
  125. */
  126.  
  127. boolean P_TeleportMove (mobj_t *thing, fixed_t x, fixed_t y)
  128. {
  129.     int                     xl,xh,yl,yh,bx,by;
  130.     subsector_t             *newsubsec;
  131.  
  132. //
  133. // kill anything occupying the position
  134. //
  135.  
  136.     tmthing = thing;
  137.     tmflags = thing->flags;
  138.  
  139.     tmx = x;
  140.     tmy = y;
  141.  
  142.     tmbbox[BOXTOP] = y + tmthing->radius;
  143.     tmbbox[BOXBOTTOM] = y - tmthing->radius;
  144.     tmbbox[BOXRIGHT] = x + tmthing->radius;
  145.     tmbbox[BOXLEFT] = x - tmthing->radius;
  146.  
  147.     newsubsec = R_PointInSubsector (x,y);
  148.     ceilingline = NULL;
  149.  
  150. //
  151. // the base floor / ceiling is from the subsector that contains the
  152. // point.  Any contacted lines the step closer together will adjust them
  153. //
  154.     tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  155.     tmceilingz = newsubsec->sector->ceilingheight;
  156.     tmfloorpic = newsubsec->sector->floorpic;
  157.  
  158.     validcount++;
  159.     numspechit = 0;
  160.  
  161. //
  162. // stomp on any things contacted
  163. //
  164.     xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  165.     xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  166.     yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  167.     yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  168.  
  169.     for (bx=xl ; bx<=xh ; bx++)
  170.         for (by=yl ; by<=yh ; by++)
  171.             if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
  172.                 return false;
  173.  
  174. //
  175. // the move is ok, so link the thing into its new position
  176. //
  177.     P_UnsetThingPosition (thing);
  178.  
  179.     thing->floorz = tmfloorz;
  180.     thing->ceilingz = tmceilingz;
  181.     thing->x = x;
  182.     thing->y = y;
  183.  
  184.     P_SetThingPosition (thing);
  185.  
  186.     return true;
  187. }
  188.  
  189.  
  190. boolean PIT_ThrustStompThing (mobj_t *thing)
  191. {
  192.     fixed_t         blockdist;
  193.  
  194.     if (!(thing->flags & MF_SHOOTABLE) )
  195.         return true;
  196.  
  197.     blockdist = thing->radius + tsthing->radius;
  198.     if ( abs(thing->x - tsthing->x) >= blockdist || 
  199.           abs(thing->y - tsthing->y) >= blockdist ||
  200.             (thing->z > tsthing->z+tsthing->height) )
  201.         return true;            // didn't hit it
  202.  
  203.     if (thing == tsthing)
  204.         return true;            // don't clip against self
  205.  
  206.     P_DamageMobj (thing, tsthing, tsthing, 10001);
  207.     tsthing->args[1] = 1;    // Mark thrust thing as bloody
  208.  
  209.     return true;
  210. }
  211.  
  212.  
  213.  
  214. void PIT_ThrustSpike(mobj_t *actor)
  215. {
  216.     int xl,xh,yl,yh,bx,by;
  217.     int x0,x2,y0,y2;
  218.  
  219.     tsthing = actor;
  220.  
  221.     x0 = actor->x - actor->info->radius;
  222.     x2 = actor->x + actor->info->radius;
  223.     y0 = actor->y - actor->info->radius;
  224.     y2 = actor->y + actor->info->radius;
  225.  
  226.     xl = (x0 - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  227.     xh = (x2 - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  228.     yl = (y0 - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  229.     yh = (y2 - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  230.  
  231.     // stomp on any things contacted
  232.     for (bx=xl ; bx<=xh ; bx++)
  233.         for (by=yl ; by<=yh ; by++)
  234.             P_BlockThingsIterator(bx,by,PIT_ThrustStompThing);
  235. }
  236.  
  237.  
  238.  
  239. /*
  240. ===============================================================================
  241.  
  242.                     MOVEMENT ITERATOR FUNCTIONS
  243.  
  244. ===============================================================================
  245. */
  246.  
  247. /*
  248. ==================
  249. =
  250. = PIT_CheckLine
  251. =
  252. = Adjusts tmfloorz and tmceilingz as lines are contacted
  253. ==================
  254. */
  255.  
  256. boolean PIT_CheckLine(line_t *ld)
  257. {
  258.     if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
  259.         ||      tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
  260.         ||      tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
  261.         ||      tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
  262.     {
  263.         return(true);
  264.     }
  265.     if(P_BoxOnLineSide(tmbbox, ld) != -1)
  266.     {
  267.         return(true);
  268.     }
  269.  
  270. // a line has been hit
  271. /*
  272. =
  273. = The moving thing's destination position will cross the given line.
  274. = If this should not be allowed, return false.
  275. = If the line is special, keep track of it to process later if the move
  276. =       is proven ok.  NOTE: specials are NOT sorted by order, so two special lines
  277. =       that are only 8 pixels apart could be crossed in either order.
  278. */
  279.  
  280.     if(!ld->backsector)
  281.     { // One sided line
  282.         if (tmthing->flags2&MF2_BLASTED)
  283.         {
  284.             P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
  285.         }
  286.         CheckForPushSpecial(ld, 0, tmthing);
  287.         return(false);
  288.     }
  289.     if(!(tmthing->flags&MF_MISSILE))
  290.     {
  291.         if(ld->flags&ML_BLOCKING)
  292.         { // Explicitly blocking everything
  293.             if (tmthing->flags2&MF2_BLASTED)
  294.             {
  295.                 P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
  296.             }
  297.             CheckForPushSpecial(ld, 0, tmthing);
  298.             return(false);
  299.         }
  300.         if(!tmthing->player && ld->flags&ML_BLOCKMONSTERS)
  301.         { // Block monsters only
  302.             if (tmthing->flags2&MF2_BLASTED)
  303.             {
  304.                 P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
  305.             }
  306.             return(false);
  307.         }
  308.     }
  309.     P_LineOpening(ld);              // set openrange, opentop, openbottom
  310.     // adjust floor / ceiling heights
  311.     if(opentop < tmceilingz)
  312.     {
  313.         tmceilingz = opentop;
  314.         ceilingline = ld;
  315.     }
  316.     if(openbottom > tmfloorz)
  317.     {
  318.         tmfloorz = openbottom;
  319.     }
  320.     if(lowfloor < tmdropoffz)
  321.     {
  322.         tmdropoffz = lowfloor;
  323.     }
  324.     if(ld->special)
  325.     { // Contacted a special line, add it to the list
  326.         spechit[numspechit] = ld;
  327.         numspechit++;
  328.     }
  329.     return(true);
  330. }
  331.  
  332. //---------------------------------------------------------------------------
  333. //
  334. // FUNC PIT_CheckThing
  335. //
  336. //---------------------------------------------------------------------------
  337.  
  338. boolean PIT_CheckThing(mobj_t *thing)
  339. {
  340.     fixed_t blockdist;
  341.     boolean solid;
  342.     int damage;
  343.  
  344.     if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
  345.     { // Can't hit thing
  346.         return(true);
  347.     }
  348.     blockdist = thing->radius+tmthing->radius;
  349.     if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist)
  350.     { // Didn't hit thing
  351.         return(true);
  352.     }
  353.     if(thing == tmthing)
  354.     { // Don't clip against self
  355.         return(true);
  356.     }
  357.     BlockingMobj = thing;
  358.      if(tmthing->flags2&MF2_PASSMOBJ)
  359.     { // check if a mobj passed over/under another object
  360.         if(tmthing->type == MT_BISHOP && thing->type == MT_BISHOP)
  361.         { // don't let bishops fly over other bishops
  362.             return false;
  363.         }
  364.         if(tmthing->z >= thing->z+thing->height
  365.             && !(thing->flags&MF_SPECIAL))
  366.         {
  367.             return(true);
  368.         }
  369.         else if(tmthing->z+tmthing->height < thing->z
  370.             && !(thing->flags&MF_SPECIAL))
  371.         { // under thing
  372.             return(true);
  373.         }
  374.     }
  375.     // Check for skulls slamming into things
  376.     if(tmthing->flags&MF_SKULLFLY)
  377.     {
  378.         if(tmthing->type == MT_MINOTAUR)
  379.         {
  380.             // Slamming minotaurs shouldn't move non-creatures
  381.             if (!(thing->flags&MF_COUNTKILL))
  382.             {
  383.                 return(false);
  384.             }
  385.         }
  386.         else if(tmthing->type == MT_HOLY_FX)
  387.         {
  388.             if(thing->flags&MF_SHOOTABLE && thing != tmthing->target)
  389.             {
  390.                 if(netgame && !deathmatch && thing->player)
  391.                 { // don't attack other co-op players
  392.                     return true;
  393.                 }
  394.                 if(thing->flags2&MF2_REFLECTIVE
  395.                     && (thing->player || thing->flags2&MF2_BOSS))
  396.                 {
  397.                     tmthing->special1 = (int)tmthing->target;
  398.                     tmthing->target = thing;
  399.                     return true;
  400.                 }
  401.                 if(thing->flags&MF_COUNTKILL || thing->player)
  402.                 {
  403.                     tmthing->special1 = (int)thing;
  404.                 }
  405.                 if(P_Random() < 96)
  406.                 {
  407.                     damage = 12;
  408.                     if(thing->player || thing->flags2&MF2_BOSS)
  409.                     {
  410.                         damage = 3;
  411.                         // ghost burns out faster when attacking players/bosses
  412.                         tmthing->health -= 6;
  413.                     }
  414.                     P_DamageMobj(thing, tmthing, tmthing->target, damage);
  415.                     if(P_Random() < 128)
  416.                     {
  417.                         P_SpawnMobj(tmthing->x, tmthing->y, tmthing->z,
  418.                             MT_HOLY_PUFF);
  419.                         S_StartSound(tmthing, SFX_SPIRIT_ATTACK);
  420.                         if(thing->flags&MF_COUNTKILL && P_Random() < 128
  421.                         && !S_GetSoundPlayingInfo(thing, SFX_PUPPYBEAT))
  422.                         {
  423.                             if ((thing->type == MT_CENTAUR) ||
  424.                                 (thing->type == MT_CENTAURLEADER) ||
  425.                                 (thing->type == MT_ETTIN))
  426.                             {
  427.                                 S_StartSound(thing, SFX_PUPPYBEAT);
  428.                             }
  429.                         }
  430.                     }
  431.                 }
  432.                 if(thing->health <= 0)
  433.                 {
  434.                     tmthing->special1 = 0;
  435.                 }
  436.             }
  437.             return true;
  438.         }
  439.         damage = ((P_Random()%8)+1)*tmthing->damage;
  440.         P_DamageMobj(thing, tmthing, tmthing, damage);
  441.         tmthing->flags &= ~MF_SKULLFLY;
  442.         tmthing->momx = tmthing->momy = tmthing->momz = 0;
  443.         P_SetMobjState(tmthing, tmthing->info->seestate);
  444.         return(false);
  445.     }
  446.     // Check for blasted thing running into another
  447.     if(tmthing->flags2&MF2_BLASTED && thing->flags&MF_SHOOTABLE)
  448.     {
  449.         if (!(thing->flags2&MF2_BOSS) &&
  450.             (thing->flags&MF_COUNTKILL))
  451.         {
  452.             thing->momx += tmthing->momx;
  453.             thing->momy += tmthing->momy;
  454.             if ((thing->momx + thing->momy) > 3*FRACUNIT)
  455.             {
  456.                 damage = (tmthing->info->mass/100)+1;
  457.                 P_DamageMobj(thing, tmthing, tmthing, damage);
  458.                 damage = (thing->info->mass/100)+1;
  459.                 P_DamageMobj(tmthing, thing, thing, damage>>2);
  460.             }
  461.             return(false);
  462.         }
  463.     }
  464.     // Check for missile
  465.     if(tmthing->flags&MF_MISSILE)
  466.     {
  467.         // Check for a non-shootable mobj
  468.         if(thing->flags2&MF2_NONSHOOTABLE)
  469.         {
  470.             return true;
  471.         }
  472.         // Check if it went over / under
  473.         if(tmthing->z > thing->z+thing->height)
  474.         { // Over thing
  475.             return(true);
  476.         }
  477.         if(tmthing->z+tmthing->height < thing->z)
  478.         { // Under thing
  479.             return(true);
  480.         }
  481.         if(tmthing->flags2&MF2_FLOORBOUNCE)
  482.         {
  483.             if(tmthing->target == thing || !(thing->flags&MF_SOLID))
  484.             {
  485.                 return true;
  486.             }
  487.             else
  488.             {
  489.                 return false;
  490.             }
  491.         }
  492.         if(tmthing->type == MT_LIGHTNING_FLOOR
  493.             || tmthing->type == MT_LIGHTNING_CEILING)
  494.         {
  495.             if(thing->flags&MF_SHOOTABLE && thing != tmthing->target)
  496.             {
  497.                 if(thing->info->mass != MAXINT)
  498.                 {
  499.                     thing->momx += tmthing->momx>>4;
  500.                     thing->momy += tmthing->momy>>4;
  501.                 }
  502.                 if((!thing->player && !(thing->flags2&MF2_BOSS))
  503.                     || !(leveltime&1))
  504.                 {
  505.                     if(thing->type == MT_CENTAUR 
  506.                     || thing->type == MT_CENTAURLEADER)
  507.                     { // Lightning does more damage to centaurs
  508.                         P_DamageMobj(thing, tmthing, tmthing->target, 9);
  509.                     }
  510.                     else
  511.                     {
  512.                         P_DamageMobj(thing, tmthing, tmthing->target, 3);
  513.                     }
  514.                     if(!(S_GetSoundPlayingInfo(tmthing, 
  515.                         SFX_MAGE_LIGHTNING_ZAP)))
  516.                     {
  517.                         S_StartSound(tmthing, SFX_MAGE_LIGHTNING_ZAP);
  518.                     }
  519.                     if(thing->flags&MF_COUNTKILL && P_Random() < 64 
  520.                     && !S_GetSoundPlayingInfo(thing, SFX_PUPPYBEAT))
  521.                     {
  522.                         if ((thing->type == MT_CENTAUR) ||
  523.                             (thing->type == MT_CENTAURLEADER) ||
  524.                             (thing->type == MT_ETTIN))
  525.                         {
  526.                             S_StartSound(thing, SFX_PUPPYBEAT);
  527.                         }
  528.                     }
  529.                 }
  530.                 tmthing->health--;
  531.                 if(tmthing->health <= 0 || thing->health <= 0)
  532.                 {
  533.                     return false;
  534.                 }
  535.                 if(tmthing->type == MT_LIGHTNING_FLOOR)
  536.                 {
  537.                     if(tmthing->special2 
  538.                         && !((mobj_t *)tmthing->special2)->special1)
  539.                     {
  540.                         ((mobj_t *)tmthing->special2)->special1 = 
  541.                             (int)thing;
  542.                     }
  543.                 }
  544.                 else if(!tmthing->special1)
  545.                 {
  546.                     tmthing->special1 = (int)thing;
  547.                 }
  548.             }
  549.             return true; // lightning zaps through all sprites
  550.         }
  551.         else if(tmthing->type == MT_LIGHTNING_ZAP)
  552.         {
  553.             mobj_t *lmo;
  554.  
  555.             if(thing->flags&MF_SHOOTABLE && thing != tmthing->target)
  556.             {            
  557.                 lmo = (mobj_t *)tmthing->special2;
  558.                 if(lmo)
  559.                 {
  560.                     if(lmo->type == MT_LIGHTNING_FLOOR)
  561.                     {
  562.                         if(lmo->special2 
  563.                             && !((mobj_t *)lmo->special2)->special1)
  564.                         {
  565.                             ((mobj_t *)lmo->special2)->special1 = (int)thing;
  566.                         }
  567.                     }
  568.                     else if(!lmo->special1)
  569.                     {
  570.                         lmo->special1 = (int)thing;
  571.                     }
  572.                     if(!(leveltime&3))
  573.                     {
  574.                         lmo->health--;
  575.                     }
  576.                 }
  577.             }
  578.         }
  579.         else if(tmthing->type == MT_MSTAFF_FX2 && thing != tmthing->target)
  580.         {
  581.             if(!thing->player && !(thing->flags2&MF2_BOSS))
  582.             {
  583.                 switch(thing->type)
  584.                 {
  585.                     case MT_FIGHTER_BOSS:    // these not flagged boss
  586.                     case MT_CLERIC_BOSS:    // so they can be blasted
  587.                     case MT_MAGE_BOSS:
  588.                         break;
  589.                     default:
  590.                         P_DamageMobj(thing, tmthing, tmthing->target, 10);
  591.                         return true;
  592.                         break;
  593.                 }
  594.             }
  595.         }
  596.         if(tmthing->target && tmthing->target->type == thing->type)
  597.         { // Don't hit same species as originator
  598.             if(thing == tmthing->target)
  599.             { // Don't missile self
  600.                 return(true);
  601.             }
  602.             if(!thing->player)
  603.             { // Hit same species as originator, explode, no damage
  604.                 return(false);
  605.             }
  606.         }
  607.         if(!(thing->flags&MF_SHOOTABLE))
  608.         { // Didn't do any damage
  609.             return!(thing->flags&MF_SOLID);
  610.         }
  611.         if(tmthing->flags2&MF2_RIP)
  612.         {
  613.             if (!(thing->flags&MF_NOBLOOD) &&
  614.                 !(thing->flags2&MF2_REFLECTIVE) &&
  615.                 !(thing->flags2&MF2_INVULNERABLE))
  616.             { // Ok to spawn some blood
  617.                 P_RipperBlood(tmthing);
  618.             }
  619.             //S_StartSound(tmthing, sfx_ripslop);
  620.             damage = ((P_Random()&3)+2)*tmthing->damage;
  621.             P_DamageMobj(thing, tmthing, tmthing->target, damage);
  622.             if(thing->flags2&MF2_PUSHABLE
  623.                 && !(tmthing->flags2&MF2_CANNOTPUSH))
  624.             { // Push thing
  625.                 thing->momx += tmthing->momx>>2;
  626.                 thing->momy += tmthing->momy>>2;
  627.             }
  628.             numspechit = 0;
  629.             return(true);
  630.         }
  631.         // Do damage
  632.         damage = ((P_Random()%8)+1)*tmthing->damage;
  633.         if(damage)
  634.         {
  635.             if (!(thing->flags&MF_NOBLOOD) && 
  636.                 !(thing->flags2&MF2_REFLECTIVE) &&
  637.                 !(thing->flags2&MF2_INVULNERABLE) &&
  638.                 !(tmthing->type == MT_TELOTHER_FX1) &&
  639.                 !(tmthing->type == MT_TELOTHER_FX2) &&
  640.                 !(tmthing->type == MT_TELOTHER_FX3) &&
  641.                 !(tmthing->type == MT_TELOTHER_FX4) &&
  642.                 !(tmthing->type == MT_TELOTHER_FX5) &&
  643.                 (P_Random() < 192))
  644.             {
  645.                 P_BloodSplatter(tmthing->x, tmthing->y, tmthing->z, thing);
  646.             }
  647.             P_DamageMobj(thing, tmthing, tmthing->target, damage);
  648.         }
  649.         return(false);
  650.     }
  651.     if(thing->flags2&MF2_PUSHABLE && !(tmthing->flags2&MF2_CANNOTPUSH))
  652.     { // Push thing
  653.         thing->momx += tmthing->momx>>2;
  654.         thing->momy += tmthing->momy>>2;
  655.     }
  656.     // Check for special thing
  657.     if(thing->flags&MF_SPECIAL)
  658.     {
  659.         solid = thing->flags&MF_SOLID;
  660.         if(tmflags&MF_PICKUP)
  661.         { // Can be picked up by tmthing
  662.             P_TouchSpecialThing(thing, tmthing); // Can remove thing
  663.         }
  664.         return(!solid);
  665.     }
  666.     return(!(thing->flags&MF_SOLID));
  667. }
  668.  
  669. //---------------------------------------------------------------------------
  670. //
  671. // PIT_CheckOnmobjZ
  672. //
  673. //---------------------------------------------------------------------------
  674.  
  675. boolean PIT_CheckOnmobjZ(mobj_t *thing)
  676. {
  677.     fixed_t blockdist;
  678.  
  679.     if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)))
  680.     { // Can't hit thing
  681.         return(true);
  682.     }
  683.     blockdist = thing->radius+tmthing->radius;
  684.     if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist)
  685.     { // Didn't hit thing
  686.         return(true);
  687.     }
  688.     if(thing == tmthing)
  689.     { // Don't clip against self
  690.         return(true);
  691.     }
  692.     if(tmthing->z > thing->z+thing->height)
  693.     {
  694.         return(true);
  695.     }
  696.     else if(tmthing->z+tmthing->height < thing->z)
  697.     { // under thing
  698.         return(true);
  699.     }
  700.     if(thing->flags&MF_SOLID)
  701.     {
  702.         onmobj = thing;
  703.     }
  704.     return(!(thing->flags&MF_SOLID));
  705. }
  706.  
  707. /*
  708. ===============================================================================
  709.  
  710.                         MOVEMENT CLIPPING
  711.  
  712. ===============================================================================
  713. */
  714.  
  715. //----------------------------------------------------------------------------
  716. //
  717. // FUNC P_TestMobjLocation
  718. //
  719. // Returns true if the mobj is not blocked by anything at its current
  720. // location, otherwise returns false.
  721. //
  722. //----------------------------------------------------------------------------
  723.  
  724. boolean P_TestMobjLocation(mobj_t *mobj)
  725. {
  726.     int flags;
  727.  
  728.     flags = mobj->flags;
  729.     mobj->flags &= ~MF_PICKUP;
  730.     if(P_CheckPosition(mobj, mobj->x, mobj->y))
  731.     { // XY is ok, now check Z
  732.         mobj->flags = flags;
  733.         if((mobj->z < mobj->floorz)
  734.             || (mobj->z+mobj->height > mobj->ceilingz))
  735.         { // Bad Z
  736.             return(false);
  737.         }
  738.         return(true);
  739.     }
  740.     mobj->flags = flags;
  741.     return(false);
  742. }
  743.  
  744. /*
  745. ==================
  746. =
  747. = P_CheckPosition
  748. =
  749. = This is purely informative, nothing is modified (except things picked up)
  750.  
  751. in:
  752. a mobj_t (can be valid or invalid)
  753. a position to be checked (doesn't need to be related to the mobj_t->x,y)
  754.  
  755. during:
  756. special things are touched if MF_PICKUP
  757. early out on solid lines?
  758.  
  759. out:
  760. newsubsec
  761. floorz
  762. ceilingz
  763. tmdropoffz = the lowest point contacted (monsters won't move to a dropoff)
  764. speciallines[]
  765. numspeciallines
  766. mobj_t *BlockingMobj = pointer to thing that blocked position (NULL if not
  767. blocked, or blocked by a line).
  768.  
  769. ==================
  770. */
  771.  
  772. boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y)
  773. {
  774.     int                     xl,xh,yl,yh,bx,by;
  775.     subsector_t             *newsubsec;
  776.  
  777.     tmthing = thing;
  778.     tmflags = thing->flags;
  779.  
  780.     tmx = x;
  781.     tmy = y;
  782.  
  783.     tmbbox[BOXTOP] = y + tmthing->radius;
  784.     tmbbox[BOXBOTTOM] = y - tmthing->radius;
  785.     tmbbox[BOXRIGHT] = x + tmthing->radius;
  786.     tmbbox[BOXLEFT] = x - tmthing->radius;
  787.  
  788.     newsubsec = R_PointInSubsector (x,y);
  789.     ceilingline = NULL;
  790.  
  791. //
  792. // the base floor / ceiling is from the subsector that contains the
  793. // point.  Any contacted lines the step closer together will adjust them
  794. //
  795.     tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  796.     tmceilingz = newsubsec->sector->ceilingheight;
  797.     tmfloorpic = newsubsec->sector->floorpic;
  798.  
  799.     validcount++;
  800.     numspechit = 0;
  801.  
  802.     if(tmflags&MF_NOCLIP && !(tmflags&MF_SKULLFLY))
  803.     {
  804.         return true;
  805.     }
  806.  
  807. //
  808. // check things first, possibly picking things up
  809. // the bounding box is extended by MAXRADIUS because mobj_ts are grouped
  810. // into mapblocks based on their origin point, and can overlap into adjacent
  811. // blocks by up to MAXRADIUS units
  812. //
  813.     xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  814.     xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  815.     yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  816.     yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  817.  
  818.     BlockingMobj = NULL;
  819.     for (bx=xl ; bx<=xh ; bx++)
  820.         for (by=yl ; by<=yh ; by++)
  821.             if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
  822.                 return false;
  823. //
  824. // check lines
  825. //
  826.     if(tmflags&MF_NOCLIP)
  827.     {
  828.         return true;
  829.     }
  830.  
  831.     BlockingMobj = NULL;
  832.     xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
  833.     xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
  834.     yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
  835.     yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
  836.  
  837.     for (bx=xl ; bx<=xh ; bx++)
  838.         for (by=yl ; by<=yh ; by++)
  839.             if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
  840.                 return false;
  841.     return true;
  842. }
  843.  
  844. //=============================================================================
  845. //
  846. // P_CheckOnmobj(mobj_t *thing)
  847. //
  848. //              Checks if the new Z position is legal
  849. //=============================================================================
  850.  
  851. mobj_t *P_CheckOnmobj(mobj_t *thing)
  852. {
  853.     int                     xl,xh,yl,yh,bx,by;
  854.     subsector_t             *newsubsec;
  855.     fixed_t x;
  856.     fixed_t y;
  857.     mobj_t oldmo;
  858.  
  859.     x = thing->x;
  860.     y = thing->y;
  861.     tmthing = thing;
  862.     tmflags = thing->flags;
  863.     oldmo = *thing; // save the old mobj before the fake zmovement
  864.     P_FakeZMovement(tmthing);
  865.  
  866.     tmx = x;
  867.     tmy = y;
  868.  
  869.     tmbbox[BOXTOP] = y + tmthing->radius;
  870.     tmbbox[BOXBOTTOM] = y - tmthing->radius;
  871.     tmbbox[BOXRIGHT] = x + tmthing->radius;
  872.     tmbbox[BOXLEFT] = x - tmthing->radius;
  873.  
  874.     newsubsec = R_PointInSubsector (x,y);
  875.     ceilingline = NULL;
  876.  
  877. //
  878. // the base floor / ceiling is from the subsector that contains the
  879. // point.  Any contacted lines the step closer together will adjust them
  880. //
  881.     tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  882.     tmceilingz = newsubsec->sector->ceilingheight;
  883.     tmfloorpic = newsubsec->sector->floorpic;
  884.  
  885.     validcount++;
  886.     numspechit = 0;
  887.  
  888.     if ( tmflags & MF_NOCLIP )
  889.         return NULL;
  890.  
  891. //
  892. // check things first, possibly picking things up
  893. // the bounding box is extended by MAXRADIUS because mobj_ts are grouped
  894. // into mapblocks based on their origin point, and can overlap into adjacent
  895. // blocks by up to MAXRADIUS units
  896. //
  897.     xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  898.     xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  899.     yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  900.     yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  901.  
  902.     for (bx=xl ; bx<=xh ; bx++)
  903.         for (by=yl ; by<=yh ; by++)
  904.             if (!P_BlockThingsIterator(bx,by,PIT_CheckOnmobjZ))
  905.             {
  906.                 *tmthing = oldmo;
  907.                 return onmobj;
  908.             }
  909.     *tmthing = oldmo;
  910.     return NULL;
  911. }
  912.  
  913. //=============================================================================
  914. //
  915. // P_FakeZMovement
  916. //
  917. //              Fake the zmovement so that we can check if a move is legal
  918. //=============================================================================
  919.  
  920. void P_FakeZMovement(mobj_t *mo)
  921. {
  922.     int dist;
  923.     int delta;
  924. //
  925. // adjust height
  926. //
  927.     mo->z += mo->momz;
  928.     if(mo->flags&MF_FLOAT && mo->target)
  929.     {       // float down towards target if too close
  930.         if(!(mo->flags&MF_SKULLFLY) && !(mo->flags&MF_INFLOAT))
  931.         {
  932.             dist = P_AproxDistance(mo->x-mo->target->x, mo->y-mo->target->y);
  933.             delta =( mo->target->z+(mo->height>>1))-mo->z;
  934.             if (delta < 0 && dist < -(delta*3))
  935.                 mo->z -= FLOATSPEED;
  936.             else if (delta > 0 && dist < (delta*3))
  937.                 mo->z += FLOATSPEED;
  938.         }
  939.     }
  940.     if(mo->player && mo->flags2&MF2_FLY && !(mo->z <= mo->floorz)
  941.         && leveltime&2)
  942.     {
  943.         mo->z += finesine[(FINEANGLES/20*leveltime>>2)&FINEMASK];
  944.     }
  945.  
  946. //
  947. // clip movement
  948. //
  949.     if(mo->z <= mo->floorz)
  950.     { // Hit the floor
  951.         mo->z = mo->floorz;
  952.         if(mo->momz < 0)
  953.         {
  954.             mo->momz = 0;
  955.         }
  956.         if(mo->flags&MF_SKULLFLY)
  957.         { // The skull slammed into something
  958.             mo->momz = -mo->momz;
  959.         }
  960.         if(mo->info->crashstate && (mo->flags&MF_CORPSE))
  961.         {
  962.             return;
  963.         }
  964.     }
  965.     else if(mo->flags2&MF2_LOGRAV)
  966.     {
  967.         if(mo->momz == 0)
  968.             mo->momz = -(GRAVITY>>3)*2;
  969.         else
  970.             mo->momz -= GRAVITY>>3;
  971.     }
  972.     else if (! (mo->flags & MF_NOGRAVITY) )
  973.     {
  974.         if (mo->momz == 0)
  975.             mo->momz = -GRAVITY*2;
  976.         else
  977.             mo->momz -= GRAVITY;
  978.     }
  979.  
  980.     if (mo->z + mo->height > mo->ceilingz)
  981.     {       // hit the ceiling
  982.         if (mo->momz > 0)
  983.             mo->momz = 0;
  984.         mo->z = mo->ceilingz - mo->height;
  985.         if (mo->flags & MF_SKULLFLY)
  986.         {       // the skull slammed into something
  987.             mo->momz = -mo->momz;
  988.         }
  989.     }
  990. }
  991.  
  992. //===========================================================================
  993. //
  994. // CheckForPushSpecial
  995. //
  996. //===========================================================================
  997.  
  998. static void CheckForPushSpecial(line_t *line, int side, mobj_t *mobj)
  999. {
  1000.     if (line->special)
  1001.     {
  1002.         if(mobj->flags2&MF2_PUSHWALL)
  1003.         {
  1004.             P_ActivateLine(line, mobj, side, SPAC_PUSH);
  1005.         }
  1006.         else if(mobj->flags2&MF2_IMPACT)
  1007.         {
  1008.             P_ActivateLine(line, mobj, side, SPAC_IMPACT);
  1009.         }    
  1010.     }
  1011. }
  1012.  
  1013. /*
  1014. ===================
  1015. =
  1016. = P_TryMove
  1017. =
  1018. = Attempt to move to a new position, crossing special lines unless MF_TELEPORT
  1019. = is set
  1020. =
  1021. ===================
  1022. */
  1023.  
  1024. boolean P_TryMove (mobj_t *thing, fixed_t x, fixed_t y)
  1025. {
  1026.     fixed_t         oldx, oldy;
  1027.     int                     side, oldside;
  1028.     line_t          *ld;
  1029.  
  1030.     floatok = false;
  1031.     if(!P_CheckPosition(thing, x, y))
  1032.     { // Solid wall or thing
  1033.         if(!BlockingMobj || BlockingMobj->player 
  1034.             || !thing->player)
  1035.         { 
  1036.             goto pushline;
  1037.         }
  1038.         else if (BlockingMobj->z+BlockingMobj->height-thing->z 
  1039.             > 24*FRACUNIT 
  1040.             || (BlockingMobj->subsector->sector->ceilingheight
  1041.             -(BlockingMobj->z+BlockingMobj->height) < thing->height)
  1042.             || (tmceilingz-(BlockingMobj->z+BlockingMobj->height) 
  1043.             < thing->height))
  1044.         {
  1045.             goto pushline;
  1046.         }
  1047.     }
  1048.     if(!(thing->flags&MF_NOCLIP))
  1049.     {
  1050.         if(tmceilingz-tmfloorz < thing->height)
  1051.         { // Doesn't fit
  1052.             goto pushline;
  1053.         }
  1054.         floatok = true;
  1055.         if(!(thing->flags&MF_TELEPORT)
  1056.             && tmceilingz-thing->z < thing->height
  1057.             && thing->type != MT_LIGHTNING_CEILING
  1058.             && !(thing->flags2&MF2_FLY))
  1059.         { // mobj must lower itself to fit
  1060.             goto pushline;
  1061.         }
  1062.         if(thing->flags2&MF2_FLY)
  1063.         {
  1064.             if(thing->z+thing->height > tmceilingz)
  1065.             {
  1066.                 thing->momz = -8*FRACUNIT;
  1067.                 goto pushline;
  1068.             }
  1069.             else if(thing->z < tmfloorz && tmfloorz-tmdropoffz > 24*FRACUNIT)
  1070.             {
  1071.                 thing->momz = 8*FRACUNIT;
  1072.                 goto pushline;
  1073.             }
  1074.         }
  1075.         if(!(thing->flags&MF_TELEPORT)
  1076.             // The Minotaur floor fire (MT_MNTRFX2) can step up any amount
  1077.             && thing->type != MT_MNTRFX2 && thing->type != MT_LIGHTNING_FLOOR
  1078.             && tmfloorz-thing->z > 24*FRACUNIT)
  1079.         {
  1080.             goto pushline;
  1081.         }
  1082.         if (!(thing->flags&(MF_DROPOFF|MF_FLOAT)) && 
  1083.             (tmfloorz-tmdropoffz > 24*FRACUNIT) &&
  1084.             !(thing->flags2&MF2_BLASTED))
  1085.         { // Can't move over a dropoff unless it's been blasted
  1086.                 return(false);
  1087.         }
  1088.         if(thing->flags2&MF2_CANTLEAVEFLOORPIC 
  1089.             && (tmfloorpic != thing->subsector->sector->floorpic
  1090.                 || tmfloorz-thing->z != 0))
  1091.         { // must stay within a sector of a certain floor type
  1092.             return false;
  1093.         }
  1094.     }
  1095.  
  1096. //
  1097. // the move is ok, so link the thing into its new position
  1098. //
  1099.     P_UnsetThingPosition (thing);
  1100.  
  1101.     oldx = thing->x;
  1102.     oldy = thing->y;
  1103.     thing->floorz = tmfloorz;
  1104.     thing->ceilingz = tmceilingz;
  1105.     thing->floorpic = tmfloorpic;
  1106.     thing->x = x;
  1107.     thing->y = y;
  1108.  
  1109.     P_SetThingPosition (thing);
  1110.  
  1111.     if(thing->flags2&MF2_FLOORCLIP)
  1112.     {
  1113.         if(thing->z == thing->subsector->sector->floorheight
  1114.             && P_GetThingFloorType(thing) >= FLOOR_LIQUID)
  1115.         {
  1116.             thing->floorclip = 10*FRACUNIT;
  1117.         }
  1118.         else 
  1119.         {
  1120.             thing->floorclip = 0;
  1121.         }
  1122.     }
  1123.  
  1124. //
  1125. // if any special lines were hit, do the effect
  1126. //
  1127.     if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
  1128.     {
  1129.         while (numspechit > 0)
  1130.         {
  1131.             numspechit--;
  1132.             // see if the line was crossed
  1133.             ld = spechit[numspechit];
  1134.             side = P_PointOnLineSide (thing->x, thing->y, ld);
  1135.             oldside = P_PointOnLineSide (oldx, oldy, ld);
  1136.             if (side != oldside)
  1137.             {
  1138.                 if (ld->special)
  1139.                 {
  1140.                     if(thing->player)
  1141.                     {
  1142.                         P_ActivateLine(ld, thing, oldside, SPAC_CROSS);
  1143.                     }
  1144.                     else if(thing->flags2&MF2_MCROSS)
  1145.                     {
  1146.                         P_ActivateLine(ld, thing, oldside, SPAC_MCROSS);
  1147.                     }
  1148.                     else if(thing->flags2&MF2_PCROSS)
  1149.                     {
  1150.                         P_ActivateLine(ld, thing, oldside, SPAC_PCROSS);
  1151.                     }
  1152.                 }
  1153.             }
  1154.         }
  1155.     }
  1156.     return true;
  1157.  
  1158. pushline:
  1159.     if(!(thing->flags&(MF_TELEPORT|MF_NOCLIP)))
  1160.     {
  1161.         int numSpecHitTemp;
  1162.  
  1163.         if (tmthing->flags2&MF2_BLASTED)
  1164.         {
  1165.             P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5);
  1166.         }
  1167.         numSpecHitTemp = numspechit;
  1168.         while (numSpecHitTemp > 0)
  1169.         {
  1170.             numSpecHitTemp--;
  1171.             // see if the line was crossed
  1172.             ld = spechit[numSpecHitTemp];
  1173.             side = P_PointOnLineSide (thing->x, thing->y, ld);
  1174.             CheckForPushSpecial(ld, side, thing);
  1175.         }
  1176.     }
  1177.     return false;
  1178. }
  1179.  
  1180. /*
  1181. ==================
  1182. =
  1183. = P_ThingHeightClip
  1184. =
  1185. = Takes a valid thing and adjusts the thing->floorz, thing->ceilingz,
  1186. = anf possibly thing->z
  1187. =
  1188. = This is called for all nearby monsters whenever a sector changes height
  1189. =
  1190. = If the thing doesn't fit, the z will be set to the lowest value and
  1191. = false will be returned
  1192. ==================
  1193. */
  1194.  
  1195. boolean P_ThingHeightClip (mobj_t *thing)
  1196. {
  1197.     boolean         onfloor;
  1198.  
  1199.     onfloor = (thing->z == thing->floorz);
  1200.  
  1201.     P_CheckPosition (thing, thing->x, thing->y);
  1202.     // what about stranding a monster partially off an edge?
  1203.  
  1204.     thing->floorz = tmfloorz;
  1205.     thing->ceilingz = tmceilingz;
  1206.     thing->floorpic = tmfloorpic;
  1207.  
  1208.     if (onfloor)
  1209.     { // walking monsters rise and fall with the floor
  1210.         if((thing->z-thing->floorz < 9*FRACUNIT) 
  1211.             || (thing->flags&MF_NOGRAVITY))
  1212.         { 
  1213.             thing->z = thing->floorz;
  1214.         }
  1215.     }
  1216.     else
  1217.     {       // don't adjust a floating monster unless forced to
  1218.         if (thing->z+thing->height > thing->ceilingz)
  1219.             thing->z = thing->ceilingz - thing->height;
  1220.     }
  1221.  
  1222.     if (thing->ceilingz - thing->floorz < thing->height)
  1223.         return false;
  1224.  
  1225.     return true;
  1226. }
  1227.  
  1228.  
  1229. /*
  1230. ==============================================================================
  1231.  
  1232.                             SLIDE MOVE
  1233.  
  1234. Allows the player to slide along any angled walls
  1235.  
  1236. ==============================================================================
  1237. */
  1238.  
  1239. fixed_t         bestslidefrac, secondslidefrac;
  1240. line_t          *bestslideline, *secondslideline;
  1241. mobj_t          *slidemo;
  1242.  
  1243. fixed_t         tmxmove, tmymove;
  1244.  
  1245. /*
  1246. ==================
  1247. =
  1248. = P_HitSlideLine
  1249. =
  1250. = Adjusts the xmove / ymove so that the next move will slide along the wall
  1251. ==================
  1252. */
  1253.  
  1254. void P_HitSlideLine (line_t *ld)
  1255. {
  1256.     int                     side;
  1257.     angle_t         lineangle, moveangle, deltaangle;
  1258.     fixed_t         movelen, newlen;
  1259.  
  1260.  
  1261.     if (ld->slopetype == ST_HORIZONTAL)
  1262.     {
  1263.         tmymove = 0;
  1264.         return;
  1265.     }
  1266.     if (ld->slopetype == ST_VERTICAL)
  1267.     {
  1268.         tmxmove = 0;
  1269.         return;
  1270.     }
  1271.  
  1272.     side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
  1273.  
  1274.     lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
  1275.     if (side == 1)
  1276.         lineangle += ANG180;
  1277.     moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
  1278.     deltaangle = moveangle-lineangle;
  1279.     if (deltaangle > ANG180)
  1280.         deltaangle += ANG180;
  1281. //              I_Error ("SlideLine: ang>ANG180");
  1282.  
  1283.     lineangle >>= ANGLETOFINESHIFT;
  1284.     deltaangle >>= ANGLETOFINESHIFT;
  1285.  
  1286.     movelen = P_AproxDistance (tmxmove, tmymove);
  1287.     newlen = FixedMul (movelen, finecosine[deltaangle]);
  1288.     tmxmove = FixedMul (newlen, finecosine[lineangle]);
  1289.     tmymove = FixedMul (newlen, finesine[lineangle]);
  1290. }
  1291.  
  1292. /*
  1293. ==============
  1294. =
  1295. = PTR_SlideTraverse
  1296. =
  1297. ==============
  1298. */
  1299.  
  1300. boolean         PTR_SlideTraverse (intercept_t *in)
  1301. {
  1302.     line_t  *li;
  1303.  
  1304.     if (!in->isaline)
  1305.         I_Error ("PTR_SlideTraverse: not a line?");
  1306.  
  1307.     li = in->d.line;
  1308.     if ( ! (li->flags & ML_TWOSIDED) )
  1309.     {
  1310.         if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
  1311.             return true;            // don't hit the back side
  1312.         goto isblocking;
  1313.     }
  1314.  
  1315.     P_LineOpening (li);                  // set openrange, opentop, openbottom
  1316.     if (openrange < slidemo->height)
  1317.         goto isblocking;                // doesn't fit
  1318.  
  1319.     if (opentop - slidemo->z < slidemo->height)
  1320.         goto isblocking;                // mobj is too high
  1321.  
  1322.     if (openbottom - slidemo->z > 24*FRACUNIT )
  1323.         goto isblocking;                // too big a step up
  1324.  
  1325.     return true;            // this line doesn't block movement
  1326.  
  1327. // the line does block movement, see if it is closer than best so far
  1328. isblocking:
  1329.     if (in->frac < bestslidefrac)
  1330.     {
  1331.         secondslidefrac = bestslidefrac;
  1332.         secondslideline = bestslideline;
  1333.         bestslidefrac = in->frac;
  1334.         bestslideline = li;
  1335.     }
  1336.  
  1337.     return false;   // stop
  1338. }
  1339.  
  1340.  
  1341. /*
  1342. ==================
  1343. =
  1344. = P_SlideMove
  1345. =
  1346. = The momx / momy move is bad, so try to slide along a wall
  1347. =
  1348. = Find the first line hit, move flush to it, and slide along it
  1349. =
  1350. = This is a kludgy mess.
  1351. ==================
  1352. */
  1353.  
  1354. void P_SlideMove (mobj_t *mo)
  1355. {
  1356.     fixed_t         leadx, leady;
  1357.     fixed_t         trailx, traily;
  1358.     fixed_t         newx, newy;
  1359.     int                     hitcount;
  1360.  
  1361.     slidemo = mo;
  1362.     hitcount = 0;
  1363. retry:
  1364.     if (++hitcount == 3)
  1365.         goto stairstep;                 // don't loop forever
  1366.  
  1367. //
  1368. // trace along the three leading corners
  1369. //
  1370.     if (mo->momx > 0)
  1371.     {
  1372.         leadx = mo->x + mo->radius;
  1373.         trailx = mo->x - mo->radius;
  1374.     }
  1375.     else
  1376.     {
  1377.         leadx = mo->x - mo->radius;
  1378.         trailx = mo->x + mo->radius;
  1379.     }
  1380.  
  1381.     if (mo->momy > 0)
  1382.     {
  1383.         leady = mo->y + mo->radius;
  1384.         traily = mo->y - mo->radius;
  1385.     }
  1386.     else
  1387.     {
  1388.         leady = mo->y - mo->radius;
  1389.         traily = mo->y + mo->radius;
  1390.     }
  1391.  
  1392.     bestslidefrac = FRACUNIT+1;
  1393.  
  1394.     P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy,
  1395.      PT_ADDLINES, PTR_SlideTraverse );
  1396.     P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy,
  1397.      PT_ADDLINES, PTR_SlideTraverse );
  1398.     P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy,
  1399.      PT_ADDLINES, PTR_SlideTraverse );
  1400.  
  1401. //
  1402. // move up to the wall
  1403. //
  1404.     if(bestslidefrac == FRACUNIT+1)
  1405.     { // the move must have hit the middle, so stairstep
  1406. stairstep:
  1407.         if(!P_TryMove(mo, mo->x, mo->y+mo->momy))
  1408.         {
  1409.             P_TryMove(mo, mo->x+mo->momx, mo->y);
  1410.         }
  1411.         return;
  1412.     }
  1413.  
  1414.     bestslidefrac -= 0x800; // fudge a bit to make sure it doesn't hit
  1415.     if (bestslidefrac > 0)
  1416.     {
  1417.         newx = FixedMul (mo->momx, bestslidefrac);
  1418.         newy = FixedMul (mo->momy, bestslidefrac);
  1419.         if (!P_TryMove (mo, mo->x+newx, mo->y+newy))
  1420.             goto stairstep;
  1421.     }
  1422.  
  1423. //
  1424. // now continue along the wall
  1425. //
  1426.     bestslidefrac = FRACUNIT-(bestslidefrac+0x800); // remainder
  1427.     if (bestslidefrac > FRACUNIT)
  1428.         bestslidefrac = FRACUNIT;
  1429.     if (bestslidefrac <= 0)
  1430.         return;
  1431.  
  1432.     tmxmove = FixedMul (mo->momx, bestslidefrac);
  1433.     tmymove = FixedMul (mo->momy, bestslidefrac);
  1434.  
  1435.     P_HitSlideLine (bestslideline);                         // clip the moves
  1436.  
  1437.     mo->momx = tmxmove;
  1438.     mo->momy = tmymove;
  1439.  
  1440.     if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove))
  1441.     {
  1442.         goto retry;
  1443.     }
  1444. }
  1445.  
  1446. //============================================================================
  1447. //
  1448. // PTR_BounceTraverse
  1449. //
  1450. //============================================================================
  1451.  
  1452. boolean PTR_BounceTraverse(intercept_t *in)
  1453. {
  1454.     line_t  *li;
  1455.  
  1456.     if (!in->isaline)
  1457.         I_Error ("PTR_BounceTraverse: not a line?");
  1458.  
  1459.     li = in->d.line;
  1460.     if (!(li->flags&ML_TWOSIDED))
  1461.     {
  1462.         if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
  1463.             return true;            // don't hit the back side
  1464.         goto bounceblocking;
  1465.     }
  1466.  
  1467.     P_LineOpening (li);                  // set openrange, opentop, openbottom
  1468.     if (openrange < slidemo->height)
  1469.         goto bounceblocking;                // doesn't fit
  1470.  
  1471.     if (opentop - slidemo->z < slidemo->height)
  1472.         goto bounceblocking;                // mobj is too high
  1473.     return true;            // this line doesn't block movement
  1474.  
  1475. // the line does block movement, see if it is closer than best so far
  1476. bounceblocking:
  1477.     if (in->frac < bestslidefrac)
  1478.     {
  1479.         secondslidefrac = bestslidefrac;
  1480.         secondslideline = bestslideline;
  1481.         bestslidefrac = in->frac;
  1482.         bestslideline = li;
  1483.     }
  1484.     return false;   // stop
  1485. }
  1486.  
  1487. //============================================================================
  1488. //
  1489. // P_BounceWall
  1490. //
  1491. //============================================================================
  1492.  
  1493. void P_BounceWall(mobj_t *mo)
  1494. {
  1495.     fixed_t         leadx, leady;
  1496.     int             side;
  1497.     angle_t         lineangle, moveangle, deltaangle;
  1498.     fixed_t         movelen;
  1499.  
  1500.     slidemo = mo;
  1501.  
  1502. //
  1503. // trace along the three leading corners
  1504. //
  1505.     if(mo->momx > 0)
  1506.     {
  1507.         leadx = mo->x+mo->radius;
  1508.     }
  1509.     else
  1510.     {
  1511.         leadx = mo->x-mo->radius;
  1512.     }
  1513.     if(mo->momy > 0)
  1514.     {
  1515.         leady = mo->y+mo->radius;
  1516.     }
  1517.     else
  1518.     {
  1519.         leady = mo->y-mo->radius;
  1520.     }
  1521.     bestslidefrac = FRACUNIT+1;
  1522.     P_PathTraverse(leadx, leady, leadx+mo->momx, leady+mo->momy,
  1523.         PT_ADDLINES, PTR_BounceTraverse);
  1524.  
  1525.     side = P_PointOnLineSide(mo->x, mo->y, bestslideline);
  1526.     lineangle = R_PointToAngle2(0, 0, bestslideline->dx,
  1527.         bestslideline->dy);
  1528.     if(side == 1)
  1529.         lineangle += ANG180;
  1530.     moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy);
  1531.     deltaangle = (2*lineangle)-moveangle;
  1532. //    if (deltaangle > ANG180)
  1533. //        deltaangle += ANG180;
  1534. //              I_Error ("SlideLine: ang>ANG180");
  1535.  
  1536.     lineangle >>= ANGLETOFINESHIFT;
  1537.     deltaangle >>= ANGLETOFINESHIFT;
  1538.  
  1539.     movelen = P_AproxDistance(mo->momx, mo->momy);
  1540.     movelen = FixedMul(movelen, 0.75*FRACUNIT); // friction
  1541.     if (movelen < FRACUNIT) movelen = 2*FRACUNIT;
  1542.     mo->momx = FixedMul(movelen, finecosine[deltaangle]);
  1543.     mo->momy = FixedMul(movelen, finesine[deltaangle]);
  1544. }
  1545.  
  1546.  
  1547. /*
  1548. ==============================================================================
  1549.  
  1550.                             P_LineAttack
  1551.  
  1552. ==============================================================================
  1553. */
  1554.  
  1555.  
  1556. mobj_t *PuffSpawned;
  1557. mobj_t          *linetarget;                    // who got hit (or NULL)
  1558. mobj_t          *shootthing;
  1559. fixed_t         shootz;                                 // height if not aiming up or down
  1560.                                     // ???: use slope for monsters?
  1561. int                     la_damage;
  1562. fixed_t         attackrange;
  1563.  
  1564. fixed_t         aimslope;
  1565.  
  1566. extern  fixed_t         topslope, bottomslope;  // slopes to top and bottom of target
  1567.  
  1568. /*
  1569. ===============================================================================
  1570. =
  1571. = PTR_AimTraverse
  1572. =
  1573. = Sets linetaget and aimslope when a target is aimed at
  1574. ===============================================================================
  1575. */
  1576.  
  1577. boolean         PTR_AimTraverse (intercept_t *in)
  1578. {
  1579.     line_t          *li;
  1580.     mobj_t          *th;
  1581.     fixed_t         slope, thingtopslope, thingbottomslope;
  1582.     fixed_t         dist;
  1583.  
  1584.     if (in->isaline)
  1585.     {
  1586.         li = in->d.line;
  1587.         if ( !(li->flags & ML_TWOSIDED) )
  1588.             return false;           // stop
  1589. //
  1590. // crosses a two sided line
  1591. // a two sided line will restrict the possible target ranges
  1592.         P_LineOpening (li);
  1593.  
  1594.         if (openbottom >= opentop)
  1595.             return false;           // stop
  1596.  
  1597.         dist = FixedMul (attackrange, in->frac);
  1598.  
  1599.         if (li->frontsector->floorheight != li->backsector->floorheight)
  1600.         {
  1601.             slope = FixedDiv (openbottom - shootz , dist);
  1602.             if (slope > bottomslope)
  1603.                 bottomslope = slope;
  1604.         }
  1605.  
  1606.         if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
  1607.         {
  1608.             slope = FixedDiv (opentop - shootz , dist);
  1609.             if (slope < topslope)
  1610.                 topslope = slope;
  1611.         }
  1612.  
  1613.         if (topslope <= bottomslope)
  1614.             return false;           // stop
  1615.  
  1616.         return true;            // shot continues
  1617.     }
  1618.  
  1619. //
  1620. // shoot a thing
  1621. //
  1622.     th = in->d.thing;
  1623.     if (th == shootthing)
  1624.         return true;            // can't shoot self
  1625.     if(!(th->flags&MF_SHOOTABLE))
  1626.     { // corpse or something
  1627.         return true;
  1628.     }
  1629.     if(th->player && netgame && !deathmatch)
  1630.     { // don't aim at fellow co-op players
  1631.         return true;
  1632.     }
  1633.  
  1634. // check angles to see if the thing can be aimed at
  1635.  
  1636.     dist = FixedMul (attackrange, in->frac);
  1637.     thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
  1638.     if (thingtopslope < bottomslope)
  1639.         return true;            // shot over the thing
  1640.     thingbottomslope = FixedDiv (th->z - shootz, dist);
  1641.     if (thingbottomslope > topslope)
  1642.         return true;            // shot under the thing
  1643.  
  1644. //
  1645. // this thing can be hit!
  1646. //
  1647.     if (thingtopslope > topslope)
  1648.         thingtopslope = topslope;
  1649.     if (thingbottomslope < bottomslope)
  1650.         thingbottomslope = bottomslope;
  1651.  
  1652.     aimslope = (thingtopslope+thingbottomslope)/2;
  1653.     linetarget = th;
  1654.  
  1655.     return false;                   // don't go any farther
  1656. }
  1657.  
  1658.  
  1659. /*
  1660. ==============================================================================
  1661. =
  1662. = PTR_ShootTraverse
  1663. =
  1664. ==============================================================================
  1665. */
  1666.  
  1667. boolean         PTR_ShootTraverse (intercept_t *in)
  1668. {
  1669.     fixed_t         x,y,z;
  1670.     fixed_t         frac;
  1671.     line_t          *li;
  1672.     mobj_t          *th;
  1673.     fixed_t         slope;
  1674.     fixed_t         dist;
  1675.     fixed_t         thingtopslope, thingbottomslope;
  1676.  
  1677.     extern mobj_t LavaInflictor;
  1678.  
  1679.     if (in->isaline)
  1680.     {
  1681.         li = in->d.line;
  1682.         if (li->special)
  1683.         {
  1684.             P_ActivateLine(li, shootthing, 0, SPAC_IMPACT);
  1685. //            P_ShootSpecialLine (shootthing, li);
  1686.         }
  1687.         if ( !(li->flags & ML_TWOSIDED) )
  1688.             goto hitline;
  1689.  
  1690. //
  1691. // crosses a two sided line
  1692. //
  1693.         P_LineOpening (li);
  1694.  
  1695.         dist = FixedMul (attackrange, in->frac);
  1696.  
  1697.         if (li->frontsector->floorheight != li->backsector->floorheight)
  1698.         {
  1699.             slope = FixedDiv (openbottom - shootz , dist);
  1700.             if (slope > aimslope)
  1701.                 goto hitline;
  1702.         }
  1703.  
  1704.         if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
  1705.         {
  1706.             slope = FixedDiv (opentop - shootz , dist);
  1707.             if (slope < aimslope)
  1708.                 goto hitline;
  1709.         }
  1710.  
  1711.         return true;            // shot continues
  1712. //
  1713. // hit line
  1714. //
  1715. hitline:
  1716.         // position a bit closer
  1717.         frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
  1718.         x = trace.x + FixedMul (trace.dx, frac);
  1719.         y = trace.y + FixedMul (trace.dy, frac);
  1720.         z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
  1721.  
  1722.         if (li->frontsector->ceilingpic == skyflatnum)
  1723.         {
  1724.             if (z > li->frontsector->ceilingheight)
  1725.                 return false;           // don't shoot the sky!
  1726.             if (li->backsector && li->backsector->ceilingpic == skyflatnum)
  1727.                 return false;           // it's a sky hack wall
  1728.         }
  1729.  
  1730.         P_SpawnPuff (x,y,z);
  1731.         return false;                   // don't go any farther
  1732.     }
  1733.  
  1734. //
  1735. // shoot a thing
  1736. //
  1737.     th = in->d.thing;
  1738.     if (th == shootthing)
  1739.         return true;            // can't shoot self
  1740.     if (!(th->flags&MF_SHOOTABLE))
  1741.         return true;            // corpse or something
  1742.  
  1743. //
  1744. // check for physical attacks on a ghost
  1745. //
  1746. /*  FIX:  Impliment Heretic 2 weapons here
  1747.     if(th->flags&MF_SHADOW && shootthing->player->readyweapon == wp_staff)
  1748.     {
  1749.         return(true);
  1750.     }
  1751. */
  1752.  
  1753. // check angles to see if the thing can be aimed at
  1754.     dist = FixedMul (attackrange, in->frac);
  1755.     thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
  1756.     if (thingtopslope < aimslope)
  1757.         return true;            // shot over the thing
  1758.     thingbottomslope = FixedDiv (th->z - shootz, dist);
  1759.     if (thingbottomslope > aimslope)
  1760.         return true;            // shot under the thing
  1761.  
  1762. //
  1763. // hit thing
  1764. //
  1765.     // position a bit closer
  1766.     frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
  1767.     x = trace.x + FixedMul(trace.dx, frac);
  1768.     y = trace.y + FixedMul(trace.dy, frac);
  1769.     z = shootz + FixedMul(aimslope, FixedMul(frac, attackrange));
  1770.     P_SpawnPuff(x, y, z);
  1771.     if(la_damage)
  1772.     {
  1773.         if (!(in->d.thing->flags&MF_NOBLOOD) &&
  1774.             !(in->d.thing->flags2&MF2_INVULNERABLE))
  1775.         {
  1776.             if(PuffType == MT_AXEPUFF || PuffType == MT_AXEPUFF_GLOW)
  1777.             {
  1778.                 P_BloodSplatter2(x, y, z, in->d.thing);
  1779.             }
  1780.             if(P_Random() < 192)
  1781.             {
  1782.                 P_BloodSplatter(x, y, z, in->d.thing);
  1783.             }
  1784.         }
  1785.         if(PuffType == MT_FLAMEPUFF2)
  1786.         { // Cleric FlameStrike does fire damage
  1787.             P_DamageMobj(th, &LavaInflictor, shootthing, la_damage);
  1788.         }
  1789.         else
  1790.         { 
  1791.             P_DamageMobj(th, shootthing, shootthing, la_damage);
  1792.         }
  1793.     }
  1794.     return(false); // don't go any farther
  1795. }
  1796.  
  1797. /*
  1798. =================
  1799. =
  1800. = P_AimLineAttack
  1801. =
  1802. =================
  1803. */
  1804.  
  1805. fixed_t P_AimLineAttack (mobj_t *t1, angle_t angle, fixed_t distance)
  1806. {
  1807.     fixed_t         x2, y2;
  1808.  
  1809.     angle >>= ANGLETOFINESHIFT;
  1810.     shootthing = t1;
  1811.     x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
  1812.     y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
  1813.     shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
  1814.     topslope = 100*FRACUNIT/160;    // can't shoot outside view angles
  1815.     bottomslope = -100*FRACUNIT/160;
  1816.     attackrange = distance;
  1817.     linetarget = NULL;
  1818.  
  1819.     P_PathTraverse ( t1->x, t1->y, x2, y2
  1820.         , PT_ADDLINES|PT_ADDTHINGS, PTR_AimTraverse );
  1821.  
  1822.     if (linetarget)
  1823.         return aimslope;
  1824.     return 0;
  1825. }
  1826.  
  1827.  
  1828.  
  1829. /*
  1830. =================
  1831. =
  1832. = P_LineAttack
  1833. =
  1834. = if damage == 0, it is just a test trace that will leave linetarget set
  1835. =
  1836. =================
  1837. */
  1838.  
  1839. void P_LineAttack (mobj_t *t1, angle_t angle, fixed_t distance, fixed_t slope, int damage)
  1840. {
  1841.     fixed_t         x2, y2;
  1842.  
  1843.     angle >>= ANGLETOFINESHIFT;
  1844.     shootthing = t1;
  1845.     la_damage = damage;
  1846.     x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
  1847.     y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
  1848.     shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
  1849.     shootz -= t1->floorclip;
  1850.     attackrange = distance;
  1851.     aimslope = slope;
  1852.  
  1853.     if(P_PathTraverse(t1->x, t1->y, x2, y2, PT_ADDLINES|PT_ADDTHINGS,
  1854.         PTR_ShootTraverse))
  1855.     {
  1856.         switch(PuffType)
  1857.         {
  1858.             case MT_PUNCHPUFF:
  1859.                 S_StartSound(t1, SFX_FIGHTER_PUNCH_MISS);
  1860.                 break;
  1861.             case MT_HAMMERPUFF:
  1862.             case MT_AXEPUFF:
  1863.             case MT_AXEPUFF_GLOW:
  1864.                 S_StartSound(t1, SFX_FIGHTER_HAMMER_MISS);
  1865.                 break;
  1866.             case MT_FLAMEPUFF:
  1867.                 P_SpawnPuff(x2, y2, shootz+FixedMul(slope, distance));
  1868.                 break;
  1869.             default:
  1870.                 break;
  1871.         }
  1872.     }
  1873. }
  1874.  
  1875. /*
  1876. ==============================================================================
  1877.  
  1878.                             USE LINES
  1879.  
  1880. ==============================================================================
  1881. */
  1882.  
  1883. mobj_t          *usething;
  1884.  
  1885. boolean         PTR_UseTraverse (intercept_t *in)
  1886. {
  1887.     int sound;
  1888.     fixed_t pheight;
  1889.  
  1890.     if (!in->d.line->special)
  1891.     {
  1892.         P_LineOpening (in->d.line);
  1893.         if (openrange <= 0)
  1894.         {
  1895.             if(usething->player)
  1896.             {
  1897.                 switch(usething->player->class)
  1898.                 {
  1899.                     case PCLASS_FIGHTER:
  1900.                         sound = SFX_PLAYER_FIGHTER_FAILED_USE;
  1901.                         break;
  1902.                     case PCLASS_CLERIC:
  1903.                         sound = SFX_PLAYER_CLERIC_FAILED_USE;
  1904.                         break;
  1905.                     case PCLASS_MAGE:
  1906.                         sound = SFX_PLAYER_MAGE_FAILED_USE;
  1907.                         break;
  1908.                     case PCLASS_PIG:
  1909.                         sound = SFX_PIG_ACTIVE1;
  1910.                         break;
  1911.                     default:
  1912.                         sound = SFX_NONE;
  1913.                         break;
  1914.                 }
  1915.                 S_StartSound(usething, sound);
  1916.             }
  1917.             return false;   // can't use through a wall
  1918.         }
  1919.         if(usething->player)
  1920.         {
  1921.             pheight = usething->z + (usething->height/2);
  1922.             if ((opentop < pheight) || (openbottom > pheight))
  1923.             {
  1924.                 switch(usething->player->class)
  1925.                 {
  1926.                     case PCLASS_FIGHTER:
  1927.                         sound = SFX_PLAYER_FIGHTER_FAILED_USE;
  1928.                         break;
  1929.                     case PCLASS_CLERIC:
  1930.                         sound = SFX_PLAYER_CLERIC_FAILED_USE;
  1931.                         break;
  1932.                     case PCLASS_MAGE:
  1933.                         sound = SFX_PLAYER_MAGE_FAILED_USE;
  1934.                         break;
  1935.                     case PCLASS_PIG:
  1936.                         sound = SFX_PIG_ACTIVE1;
  1937.                         break;
  1938.                     default:
  1939.                         sound = SFX_NONE;
  1940.                         break;
  1941.                 }
  1942.                 S_StartSound(usething, sound);
  1943.             }
  1944.         }
  1945.         return true ;           // not a special line, but keep checking
  1946.     }
  1947.  
  1948.     if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
  1949.         return false;           // don't use back sides
  1950.  
  1951. //    P_UseSpecialLine (usething, in->d.line);
  1952.     P_ActivateLine(in->d.line, usething, 0, SPAC_USE);
  1953.  
  1954.     return false;                   // can't use for than one special line in a row
  1955. }
  1956.  
  1957.  
  1958. /*
  1959. ================
  1960. =
  1961. = P_UseLines
  1962. =
  1963. = Looks for special lines in front of the player to activate
  1964. ================
  1965. */
  1966.  
  1967. void P_UseLines (player_t *player)
  1968. {
  1969.     int                     angle;
  1970.     fixed_t         x1, y1, x2, y2;
  1971.  
  1972.     usething = player->mo;
  1973.  
  1974.     angle = player->mo->angle >> ANGLETOFINESHIFT;
  1975.     x1 = player->mo->x;
  1976.     y1 = player->mo->y;
  1977.     x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
  1978.     y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
  1979.  
  1980.     P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
  1981. }
  1982.  
  1983. //==========================================================================
  1984. //
  1985. // PTR_PuzzleItemTraverse
  1986. //
  1987. //==========================================================================
  1988.  
  1989. #define USE_PUZZLE_ITEM_SPECIAL 129
  1990.  
  1991. static mobj_t *PuzzleItemUser;
  1992. static int PuzzleItemType;
  1993. static boolean PuzzleActivated;
  1994.  
  1995. boolean PTR_PuzzleItemTraverse(intercept_t *in)
  1996. {
  1997.     mobj_t *mobj;
  1998.     int sound;
  1999.  
  2000.     if(in->isaline)
  2001.     { // Check line
  2002.         if(in->d.line->special != USE_PUZZLE_ITEM_SPECIAL)
  2003.         {
  2004.             P_LineOpening(in->d.line);
  2005.             if(openrange <= 0)
  2006.             {
  2007.                 sound = SFX_NONE;
  2008.                 if(PuzzleItemUser->player)
  2009.                 {
  2010.                     switch(PuzzleItemUser->player->class)
  2011.                     {
  2012.                         case PCLASS_FIGHTER:
  2013.                             sound = SFX_PUZZLE_FAIL_FIGHTER;
  2014.                             break;
  2015.                         case PCLASS_CLERIC:
  2016.                             sound = SFX_PUZZLE_FAIL_CLERIC;
  2017.                             break;
  2018.                         case PCLASS_MAGE:
  2019.                             sound = SFX_PUZZLE_FAIL_MAGE;
  2020.                             break;
  2021.                         default:
  2022.                             sound = SFX_NONE;
  2023.                             break;
  2024.                     }
  2025.                 }
  2026.                 S_StartSound(PuzzleItemUser, sound);
  2027.                 return false; // can't use through a wall
  2028.             }
  2029.             return true; // Continue searching
  2030.         }
  2031.         if(P_PointOnLineSide(PuzzleItemUser->x, PuzzleItemUser->y,
  2032.             in->d.line) == 1)
  2033.         { // Don't use back sides
  2034.             return false;
  2035.         }
  2036.         if(PuzzleItemType != in->d.line->arg1)
  2037.         { // Item type doesn't match
  2038.             return false;
  2039.         }
  2040.         P_StartACS(in->d.line->arg2, 0, &in->d.line->arg3,
  2041.             PuzzleItemUser, in->d.line, 0);
  2042.         in->d.line->special = 0;
  2043.         PuzzleActivated = true;
  2044.         return false; // Stop searching
  2045.     }
  2046.     // Check thing
  2047.     mobj = in->d.thing;
  2048.     if(mobj->special != USE_PUZZLE_ITEM_SPECIAL)
  2049.     { // Wrong special
  2050.         return true;
  2051.     }
  2052.     if(PuzzleItemType != mobj->args[0])
  2053.     { // Item type doesn't match
  2054.         return true;
  2055.     }
  2056.     P_StartACS(mobj->args[1], 0, &mobj->args[2], PuzzleItemUser, NULL, 0);
  2057.     mobj->special = 0;
  2058.     PuzzleActivated = true;
  2059.     return false; // Stop searching
  2060. }
  2061.  
  2062. //==========================================================================
  2063. //
  2064. // P_UsePuzzleItem
  2065. //
  2066. // Returns true if the puzzle item was used on a line or a thing.
  2067. //
  2068. //==========================================================================
  2069.  
  2070. boolean P_UsePuzzleItem(player_t *player, int itemType)
  2071. {
  2072.     int angle;
  2073.     fixed_t x1, y1, x2, y2;
  2074.  
  2075.     PuzzleItemType = itemType;
  2076.     PuzzleItemUser = player->mo;
  2077.     PuzzleActivated = false;
  2078.     angle = player->mo->angle>>ANGLETOFINESHIFT;
  2079.     x1 = player->mo->x;
  2080.     y1 = player->mo->y;
  2081.     x2 = x1+(USERANGE>>FRACBITS)*finecosine[angle];
  2082.     y2 = y1+(USERANGE>>FRACBITS)*finesine[angle];
  2083.     P_PathTraverse(x1, y1, x2, y2, PT_ADDLINES|PT_ADDTHINGS,
  2084.         PTR_PuzzleItemTraverse);
  2085.     return PuzzleActivated;
  2086. }
  2087.  
  2088. /*
  2089. ==============================================================================
  2090.  
  2091.                             RADIUS ATTACK
  2092.  
  2093. ==============================================================================
  2094. */
  2095.  
  2096. mobj_t *bombsource;
  2097. mobj_t *bombspot;
  2098. int bombdamage;
  2099. int bombdistance;
  2100. boolean DamageSource;
  2101.  
  2102. /*
  2103. =================
  2104. =
  2105. = PIT_RadiusAttack
  2106. =
  2107. = Source is the creature that casued the explosion at spot
  2108. =================
  2109. */
  2110.  
  2111. boolean PIT_RadiusAttack (mobj_t *thing)
  2112. {
  2113.     fixed_t dx, dy, dist;
  2114.     int damage;
  2115.  
  2116.     if(!(thing->flags&MF_SHOOTABLE))
  2117.     {
  2118.         return true;
  2119.     }
  2120. //    if(thing->flags2&MF2_BOSS)
  2121. //    {    // Bosses take no damage from PIT_RadiusAttack
  2122. //        return(true);
  2123. //    }
  2124.     if(!DamageSource && thing == bombsource)
  2125.     { // don't damage the source of the explosion
  2126.         return true;
  2127.     }
  2128.     if(abs((thing->z-bombspot->z)>>FRACBITS) > 2*bombdistance)
  2129.     { // too high/low
  2130.         return true;
  2131.     }
  2132.     dx = abs(thing->x-bombspot->x);
  2133.     dy = abs(thing->y-bombspot->y);
  2134.     dist = dx > dy ? dx : dy;
  2135.     dist = (dist-thing->radius)>>FRACBITS;
  2136.     if(dist < 0)
  2137.     {
  2138.         dist = 0;
  2139.     }
  2140.     if(dist >= bombdistance)
  2141.     { // Out of range
  2142.         return true;
  2143.     }
  2144.     if(P_CheckSight(thing, bombspot))
  2145.     { // OK to damage, target is in direct path
  2146.         damage = (bombdamage*(bombdistance-dist)/bombdistance)+1;
  2147.         if(thing->player)
  2148.         {
  2149.             damage >>= 2;
  2150.         }
  2151.         P_DamageMobj(thing, bombspot, bombsource, damage);
  2152.     }
  2153.     return(true);
  2154. }
  2155.  
  2156. /*
  2157. =================
  2158. =
  2159. = P_RadiusAttack
  2160. =
  2161. = Source is the creature that caused the explosion at spot
  2162. =================
  2163. */
  2164.  
  2165. void P_RadiusAttack (mobj_t *spot, mobj_t *source, int damage, int distance,
  2166.     boolean damageSource)
  2167. {
  2168.     int                     x,y, xl, xh, yl, yh;
  2169.     fixed_t         dist;
  2170.  
  2171.     dist = (distance+MAXRADIUS)<<FRACBITS;
  2172.     yh = (spot->y+dist-bmaporgy)>>MAPBLOCKSHIFT;
  2173.     yl = (spot->y-dist-bmaporgy)>>MAPBLOCKSHIFT;
  2174.     xh = (spot->x+dist-bmaporgx)>>MAPBLOCKSHIFT;
  2175.     xl = (spot->x-dist-bmaporgx)>>MAPBLOCKSHIFT;
  2176.     bombspot = spot;
  2177.     bombsource = source;
  2178.     bombdamage = damage;
  2179.     bombdistance = distance;
  2180.     DamageSource = damageSource;
  2181.     for (y = yl; y <= yh; y++)
  2182.     {
  2183.         for (x = xl; x <= xh; x++)
  2184.         {
  2185.             P_BlockThingsIterator(x, y, PIT_RadiusAttack);
  2186.         }
  2187.     }
  2188. }
  2189.  
  2190. /*
  2191. ==============================================================================
  2192.  
  2193.                         SECTOR HEIGHT CHANGING
  2194.  
  2195. = After modifying a sectors floor or ceiling height, call this
  2196. = routine to adjust the positions of all things that touch the
  2197. = sector.
  2198. =
  2199. = If anything doesn't fit anymore, true will be returned.
  2200. = If crunch is true, they will take damage as they are being crushed
  2201. = If Crunch is false, you should set the sector height back the way it
  2202. = was and call P_ChangeSector again to undo the changes
  2203. ==============================================================================
  2204. */
  2205.  
  2206. int         crushchange;
  2207. boolean         nofit;
  2208.  
  2209. /*
  2210. ===============
  2211. =
  2212. = PIT_ChangeSector
  2213. =
  2214. ===============
  2215. */
  2216.  
  2217. boolean PIT_ChangeSector (mobj_t *thing)
  2218. {
  2219.     mobj_t          *mo;
  2220.  
  2221.     if (P_ThingHeightClip (thing))
  2222.         return true;            // keep checking
  2223.  
  2224.     // crunch bodies to giblets
  2225.     if ((thing->flags&MF_CORPSE) && (thing->health <= 0))
  2226.     {
  2227.         if (thing->flags&MF_NOBLOOD)
  2228.         {
  2229.             P_RemoveMobj (thing);
  2230.         }
  2231.         else
  2232.         {
  2233.             if (thing->state != &states[S_GIBS1])
  2234.             {
  2235.                 P_SetMobjState (thing, S_GIBS1);
  2236.                 thing->height = 0;
  2237.                 thing->radius = 0;
  2238.                 S_StartSound(thing, SFX_PLAYER_FALLING_SPLAT);
  2239.             }
  2240.         }
  2241.         return true;            // keep checking
  2242.     }
  2243.  
  2244.     // crunch dropped items
  2245.     if (thing->flags2&MF2_DROPPED)
  2246.     {
  2247.         P_RemoveMobj (thing);
  2248.         return true;            // keep checking
  2249.     }
  2250.  
  2251.     if (! (thing->flags & MF_SHOOTABLE) )
  2252.         return true;                            // assume it is bloody gibs or something
  2253.  
  2254.     nofit = true;
  2255.     if (crushchange && !(leveltime&3))
  2256.     {
  2257.         P_DamageMobj(thing, NULL, NULL, crushchange);
  2258.         // spray blood in a random direction
  2259.         if ((!(thing->flags&MF_NOBLOOD)) &&
  2260.             (!(thing->flags2&MF2_INVULNERABLE)))
  2261.         {
  2262.             mo = P_SpawnMobj (thing->x, thing->y, thing->z + thing->height/2, 
  2263.                 MT_BLOOD);
  2264.             mo->momx = (P_Random() - P_Random ())<<12;
  2265.             mo->momy = (P_Random() - P_Random ())<<12;
  2266.         }
  2267.     }
  2268.  
  2269.     return true;            // keep checking (crush other things)
  2270. }
  2271.  
  2272. /*
  2273. ===============
  2274. =
  2275. = P_ChangeSector
  2276. =
  2277. ===============
  2278. */
  2279.  
  2280. boolean P_ChangeSector (sector_t *sector, int crunch)
  2281. {
  2282.     int                     x,y;
  2283.  
  2284.     nofit = false;
  2285.     crushchange = crunch;
  2286.  
  2287. // recheck heights for all things near the moving sector
  2288.  
  2289.     for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
  2290.         for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
  2291.             P_BlockThingsIterator (x, y, PIT_ChangeSector);
  2292.  
  2293.  
  2294.     return nofit;
  2295. }
  2296.  
  2297.